﻿const path = require('path');
const fs = require("fs");
const http = require("http")
const Server = require('node-git-server');
const YAML = require("yaml");
const { encryptPassword } = require('./encrypt');
const { readAccountCfg } = require('./cfg');
const {
    argv,
} = require('yargs');
let bootstrapConfig = require('./bootstrap').bootstrapConfig;



const repos = new Server(bootstrapConfig.repositoriesFolder, {
    autoCreate: false,
    authenticate: (type, repo, user, next) => {
        var requirePrivileges = [];
        switch (type) {
            case 'push':
                requirePrivileges.push(Privilege.Push);
                break;
            case 'fetch':
                requirePrivileges.push(Privilege.Fetch);
                break;
            default:
                requirePrivileges.push(Privilege.Fetch | Privilege.Push);
                break;
        }
        user((username, password) => {
            if (argv.TRUST_ALL) {
                next();
                return;
            }
            password = encryptPassword(password);
            console.log(username, password);
            var userInfo = getUser(username);
            if (!userInfo) {
                return next("You have no privilege!");
            }
            if (userInfo.pwd !== password) {
                return next("You have no privilege!");
            }
            if (!userInfo.hasPrivileges(requirePrivileges)) {
                return next("You have no privilege!");
            }
            next();
        });
    }
});
const port = bootstrapConfig.port;

// 修改工作目录为当前文件目录
process.chdir(path.resolve(__dirname));


console.log("Current Working Directory:", process.cwd());


repos.on('push', (req) => {
    console.log(`push ${req.repo} (${req.branch}) ${req.commit}`);
    req.accept();

    // 添加 webhook
    handleWebhook(req.repo, req.branch, req.commit);
});

repos.on('fetch', (req) => {
    console.log(`fetch ${req.repo} ${req.commit}`);
    req.accept();
});

repos.listen(port, () => {
    console.log(`node-git-server running at http://localhost:${port}`)
});



var User = (function () {
    function User(username, pwd, privilege) {
        this.username = username;
        this.pwd = pwd;
        this.privilege = privilege;
    };
    User.prototype.hasPrivilege = function (privilege) {
        return this.privilege & privilege;
    };
    User.prototype.hasPrivileges = function (privileges) {
        var scope = this;
        return privileges.every(function (privilege) {
            return scope.hasPrivilege(privilege);
        });
    };
    return User;
})();

var Privilege = {
    Fetch: 1,
    Push: 2,
};

var staticUsers = {};

function addUser(username, pwd, privilege) {
    var user = new User(username, pwd, privilege);
    staticUsers[user.username] = user;
};
/**
 * 
 * @param {*} username 
 * @returns {User}
 */
function getUser(username) {
    var user = staticUsers[username];
    if (!user) {
        // 读取account.json
        var accountData = readAccountCfg();
        if (accountData) {
            var userCount = accountData.users.length;
            for (var i = 0; i < userCount; ++i) {
                user = accountData.users[i];
                if (user.username === username) {
                    user = new User(user.username, user.password, user.privilege || 0);
                    break;
                }
            }
        }
        if (user) {
            let groups = accountData.groups;
            for (let i = 0; i < groups.length; i++) {
                const group = groups[i];
                if (group.users.includes(user.username)) {
                    user.privilege = Math.max(user.privilege, group.privilege || 0);
                    break;
                }
            }
        }
    }
    return user;
}

function handleWebhook(repo, branch, commit) {
    try {
        var webhookStr = fs.readFileSync('./cfg/webhook.yml', {
            encoding: "utf-8"
        });
        var webhookData = YAML.parse(webhookStr);
        // console.info(webhookData);
        var hooks = webhookData.hooks;
        var hookDatas = hooks && hooks[repo];
        if (hookDatas) {
            for (var hookData of hookDatas) {
                var req = http.request(
                    new URL(hookData.url), {
                        method: hookData.method
                    },
                    function (res) {
                        res.setEncoding('utf8');
                        res.on('data', function (chunk) {
                            console.info('Response of hook:' + chunk)
                        });
                    }
                );
                req.end(() => {
                    console.info('Finish hook!')
                });
            }
        }
    } catch (error) {
        console.error("Read webhook error", error);
    }
}

// addUser("Tsubasa", "27894869", Privilege.Fetch | Privilege.Push);

readAccountCfg();